package com.fcc.wfly.solution.controller;

import com.fcc.wfly.entitlement.hal.EventSolutionsJson;
import com.fcc.wfly.common.domain.ErrorHandleConst;
import com.fcc.wfly.common.domain.RestApiRequestTrack;
import com.fcc.wfly.entitlement.domain.EventSolution;
import com.fcc.wfly.entitlement.domain.SolutionFeedBack;
import com.fcc.wfly.entitlement.hal.SolutionJson;
import com.fcc.wfly.solution.controller.dao.SolutionDao;
import com.fcc.wfly.solution.controller.service.SolutionService;
import com.fcc.wfly.utils.AuthUtils;
import org.apache.commons.collections.map.MultiValueMap;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

@RestController
public class SolutionController {

	protected Logger logger = LoggerFactory.getLogger(getClass());

	public static final String HEADER_DATE = "Date";
	public static final String HEADER_CONTENT_TYPE = "Content-Type";
	public static final String HEADER_CONTENT_LENGTH = "Content-Length";
	public static final String HEADER_USER_AGENT = "User-Agent";
	public static final String HEADER_CACHE_CONTROL = "Cache-Control";
	public static final String PRODUCTION_NUMBER = "PN";
	public static final String SERIAL_NUMBER = "SN";
	public static final String EVENT_CODE = "eventCode";
	public static final String DETECTION_DATE = "detectionDate";
	public static final String LANGUAGE = "Accept-Language";
	public static final String ACCEPT_ENCODING = "Accept-Encoding";
	public static final String COOKIE = "Cookie";
	public static final String SOLUTION_ID = "solutionID";
	public static final String SCORE = "score";
	public static final String FEEDBACK = "feedback";

	@Autowired
	private SolutionService solutionService;

	@Autowired
	private SolutionDao solutionDao;
	private MultiValueMap res;

	private boolean validate;

	@RequestMapping("/GetSolution")
	public HttpEntity<EventSolutionsJson> getSolution(HttpServletRequest request, HttpServletResponse response) throws ParseException, InvocationTargetException, IllegalAccessException, IOException {
		Logger logger = LoggerFactory.getLogger(getClass());

		if (AuthUtils.auth(request)) {
			Date requestTime = new Date();
			String pn = request.getParameter("PN");
			String sn = request.getParameter("SN");
			String eventCode = request.getParameter(EVENT_CODE);
			String date = request.getParameter(DETECTION_DATE);
			
			// Error Handle - Params Validation
            try {
            	ErrorHandleConst.SolutionParamsValidate(pn,sn,eventCode,date);
            } catch (Exception e) {
				if (e.getMessage()==ErrorHandleConst.PN_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SN_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SN_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.PN_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.DATE_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.DATE_ERROR_FORMAT){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.DURING_TIME){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.EVENT_CODE_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.EVENT_CODE_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "GetSolution", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				return new ResponseEntity(res, HttpStatus.BAD_REQUEST);
            }
			//Boolean validate = validateSolutionParameter(eventCode, response);
			EventSolutionsJson solutionFeedBackJsons = new EventSolutionsJson();
			if (validate) {
				List<EventSolution> eventSolutions = solutionService.getSolution(pn, eventCode);
				List<SolutionJson> solutionsJson = new ArrayList<>();
				if (!eventSolutions.isEmpty()) {
					for (EventSolution eventSolution : eventSolutions) {
						SolutionJson solutionJson = new SolutionJson();
						solutionJson.setSolution_ID(eventSolution.getSolutionId());
						solutionJson.setPrinter_Family(eventSolution.getPrinterFamily());
						solutionJson.setEvent_Code(eventSolution.getEventCode());
						solutionJson.setShort_Description(eventSolution.getShortDescription());
						solutionJson.setLong_Description(eventSolution.getLongDescription());
						solutionJson.setPossible_Cause(eventSolution.getPossibleCause());
						solutionJson.setCorrective_Action(eventSolution.getCorrectiveAction());
						solutionJson.setParts_Requested(StringUtils.isBlank(eventSolution.getPartsRequested()) ? "under development" : eventSolution.getPartsRequested());
						solutionJson.setSeverity(eventSolution.getSeverity());
						solutionJson.setLanguage_Code(eventSolution.getLanguageCode());
						solutionJson.setUpdate_TS(eventSolution.getInsertTs().replace(" ", "T") + "Z");
						solutionsJson.add(solutionJson);
					}
					solutionFeedBackJsons.setSolutionJson(solutionsJson);
				}
				// solutionFeedBackJsons.add(linkTo(methodOn(SolutionController.class).getSolution(request,
				// response)).withSelfRel());
				Date responseTime = new Date();
				this.addHeaderInfoSolution(request, pn, sn, eventCode, date, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(requestTime), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(responseTime), Thread.currentThread().getStackTrace()[1].getMethodName());
				return new ResponseEntity<EventSolutionsJson>(solutionFeedBackJsons, HttpStatus.OK);
			}
			return new ResponseEntity<EventSolutionsJson>(HttpStatus.BAD_REQUEST);
		} else {
			return new ResponseEntity<EventSolutionsJson>(HttpStatus.UNAUTHORIZED);
		}

	}

	@RequestMapping(value = "/PostSolutionFeedback", method = RequestMethod.POST)
	public void postSolutionFeedback(HttpServletRequest request, @RequestHeader(value = "PN") String pn, @RequestHeader(value = "SN") String sn, @RequestHeader(value = "eventCode") String eventCode, @RequestHeader(value = "detectionDate") String date, @RequestHeader(value = "solutionID") String solutionId, @RequestHeader(value = "feedback") String feedback, @RequestHeader(value = "score") String score, HttpServletResponse response) throws ParseException, InvocationTargetException, IllegalAccessException, IOException {
		if (AuthUtils.auth(request)) {
			//boolean validate = validateFeedBackParameter(pn, sn, eventCode, date, solutionId, feedback, score, response);
			
            // Error Handle - Params Validation
            try {
            	validate = ErrorHandleConst.PostSolutionParamsValidate(pn,sn,eventCode,date,solutionId,feedback,score,response);
            } catch (Exception e) {
				if (e.getMessage()==ErrorHandleConst.PN_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SN_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SN_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.PN_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.DATE_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.DATE_ERROR_FORMAT){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.DURING_TIME){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.EVENT_CODE_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.EVENT_CODE_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SOLUTIONID_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SOLUTIONID_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.FEEDBACK_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.FEEDBACK_OVER_LIMIT){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SCORE_NOT_EMPTY){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SCORE_NOT_INT){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				else if(e.getMessage()==ErrorHandleConst.SCORE_LIMIT){
					logger.info("【{}】Bad Request:{}", "PostSolutionFeedback", e.getMessage());
					res = new MultiValueMap();
					res.put("error", e.getMessage());
				}
				response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
				PrintWriter out = response.getWriter();
				out.println("error: "+res.get("error"));
				validate=false;
            }            
            
			if (validate) {
				SolutionFeedBack solutionFeedBack = new SolutionFeedBack();
				solutionFeedBack.setProductionNumber(pn);
				solutionFeedBack.setSerialNumber(sn);
				solutionFeedBack.setEventCode(eventCode);
				Date detectionDate = getDetectionDate(date);
				solutionFeedBack.setDetectionTime(detectionDate);
				solutionFeedBack.setSolutionId(solutionId);
				solutionFeedBack.setScore(score);
				solutionFeedBack.setFeedBack(feedback);
				solutionFeedBack.setInsertTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
				solutionDao.addFeedBack(solutionFeedBack);
				String responseTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
				this.addHeaderInfoFeedBack(request, pn, sn, eventCode, date, solutionId, feedback, score, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), responseTime, Thread.currentThread().getStackTrace()[1].getMethodName());
			}
		} else {
			response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
		}
	}

	private synchronized void addHeaderInfoSolution(HttpServletRequest request, String pn, String sn, String eventCode, String detectionDate, String requestTime, String responseTime, String methodName) {
		RestApiRequestTrack track = new RestApiRequestTrack();
		track.setClientId(request.getRemoteAddr());
		JSONObject requestParameter = new JSONObject();
		requestParameter.put(PRODUCTION_NUMBER, pn);
		requestParameter.put(SERIAL_NUMBER, sn);
		requestParameter.put(EVENT_CODE, eventCode);
		requestParameter.put(DETECTION_DATE, detectionDate);
		track.setRequestParameter(requestParameter.toString());
		JSONObject requestHeader = new JSONObject();
		requestHeader.put(HEADER_DATE, request.getHeader(HEADER_DATE));
		requestHeader.put(LANGUAGE, request.getHeader(LANGUAGE));
		requestHeader.put(ACCEPT_ENCODING, request.getHeader(ACCEPT_ENCODING));
		requestHeader.put(COOKIE, request.getHeader(COOKIE));
		requestHeader.put(HEADER_CONTENT_TYPE, request.getHeader(HEADER_CONTENT_TYPE));
		requestHeader.put(HEADER_USER_AGENT, request.getHeader(HEADER_USER_AGENT));
		requestHeader.put(HEADER_CONTENT_LENGTH, request.getHeader(HEADER_CONTENT_LENGTH));
		requestHeader.put(HEADER_CACHE_CONTROL, request.getHeader(HEADER_CACHE_CONTROL));
		track.setRequestHeader(requestHeader.toString());
		track.setRequestTime(requestTime);
		track.setResponseTime(responseTime);
		track.setApiName(methodName);
		track.setInsertTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		solutionDao.addRequestLog(track);
	}

	private synchronized void addHeaderInfoFeedBack(HttpServletRequest request, String pn, String sn, String eventCode, String date, String solutionId, String feedback, String score, String requestTime, String responseTime, String methodName) {
		RestApiRequestTrack track = new RestApiRequestTrack();
		track.setClientId(request.getRemoteAddr());
		JSONObject requestParameter = new JSONObject();
		requestParameter.put(PRODUCTION_NUMBER, pn);
		requestParameter.put(SERIAL_NUMBER, sn);
		requestParameter.put(EVENT_CODE, eventCode);
		requestParameter.put(DETECTION_DATE, date);
		requestParameter.put(SOLUTION_ID, solutionId);
		requestParameter.put(SCORE, score);
		requestParameter.put(FEEDBACK, feedback);
		track.setRequestParameter(requestParameter.toString());
		JSONObject requestHeader = new JSONObject();
		requestHeader.put(HEADER_DATE, request.getHeader(HEADER_DATE));
		requestHeader.put(LANGUAGE, request.getHeader(LANGUAGE));
		requestHeader.put(ACCEPT_ENCODING, request.getHeader(ACCEPT_ENCODING));
		requestHeader.put(COOKIE, request.getHeader(COOKIE));
		requestHeader.put(HEADER_CONTENT_TYPE, request.getHeader(HEADER_CONTENT_TYPE));
		requestHeader.put(HEADER_USER_AGENT, request.getHeader(HEADER_USER_AGENT));
		requestHeader.put(HEADER_CONTENT_LENGTH, request.getHeader(HEADER_CONTENT_LENGTH));
		requestHeader.put(HEADER_CACHE_CONTROL, request.getHeader(HEADER_CACHE_CONTROL));
		track.setRequestHeader(requestHeader.toString());
		track.setRequestTime(requestTime);
		track.setResponseTime(responseTime);
		track.setApiName(methodName);
		track.setInsertTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		solutionDao.addRequestLog(track);
	}

	private Date getDetectionDate(String date) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
		sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
		return date == null ? null : sdf.parse(date);
	}

/* Not useful anymore
	private Boolean validateFeedBackParameter(String pn, String sn, String eventCode, String date, String solutionId, String feedback, String score, HttpServletResponse response) throws IOException {
		if (StringUtils.isEmpty(pn)) {
			response.sendError(201, "PN not allow empty");
			return false;
		}
		if (pn.length()>10){
			response.sendError(201, "PN length should not over 10");
			return false;
		}
		if (StringUtils.isEmpty(sn)) {
			response.sendError(202, "SN not allow empty");
			return false;
		}
		if (StringUtils.isEmpty(eventCode)) {
			response.sendError(203, "eventCode not allow empty");
			return false;
		}
		if (StringUtils.isEmpty(date)) {
			response.sendError(204, "detectionDate not allow empty");
			return false;
		}
		if (StringUtils.isEmpty(score) || !isNum(score.trim()) ) {
			response.sendError(205, "Parameter Score is incorrect");
			return false;
		}
		return true;
	}
	
	private Boolean validateSolutionParameter(String eventCode, HttpServletResponse response) throws IOException {
		if (StringUtils.isEmpty(eventCode)) {
			response.sendError(203, "eventCode not allow empty");
			return false;
		}
		return true;
	}
*/

	private static boolean isNum(String str) {
		return str.matches("^[-+]?(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)$");
	}
}
